import os

from django.contrib.auth.models import User
from django.db import models
from django.utils import timezone

# 支持的编程语言选项
LANGUAGE_CHOICES = [
    ('python', 'Python'),
    ('typescript', 'TypeScript'),
    ('javascript', 'JavaScript'),
    ('lua', 'Lua'),
]


class CodeManager(models.Manager):
    """代码模型的自定义管理器，支持软删除"""
    
    def get_queryset(self):
        """默认查询集，排除已删除的代码"""
        return super().get_queryset().filter(is_deleted=False)
    
    def all_with_deleted(self):
        """获取包含已删除代码的查询集"""
        return super().get_queryset()
    
    def deleted_only(self):
        """只获取已删除的代码"""
        return super().get_queryset().filter(is_deleted=True)


class Code(models.Model):
    """代码模型，存储代码的基本信息"""

    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='codes', verbose_name='用户')
    title = models.CharField(max_length=100, verbose_name='标题')
    description = models.TextField(blank=True, null=True, verbose_name='描述')
    language = models.CharField(
        max_length=20, default=LANGUAGE_CHOICES[0][0], choices=LANGUAGE_CHOICES, verbose_name='编程语言'
    )
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    is_active = models.BooleanField(default=True, verbose_name='是否激活')
    is_public = models.BooleanField(default=True, verbose_name='是否公开接受挑战')
    is_starred = models.BooleanField(default=False, verbose_name='是否星标（用于世界杯比赛）')
    
    # 软删除字段
    is_deleted = models.BooleanField(default=False, verbose_name='是否已删除')
    deleted_at = models.DateTimeField(null=True, blank=True, verbose_name='删除时间')
    
    # 自定义管理器
    objects = CodeManager()  # 默认管理器，排除已删除的代码
    all_objects = models.Manager()  # 包含所有代码的管理器

    class Meta:
        verbose_name = '代码'
        verbose_name_plural = '代码'
        ordering = ['-updated_at']

    def __str__(self):
        return f'{self.title} ({self.get_language_display()})'

    def save(self, *args, **kwargs):
        # 如果当前代码被设置为星标，则取消其他用户代码的星标状态
        if self.is_starred:
            Code.all_objects.filter(user=self.user, is_starred=True).exclude(pk=self.pk).update(is_starred=False)
        super().save(*args, **kwargs)

    def get_latest_version(self):
        """获取最新版本的代码"""
        return self.versions.order_by('-version_number').first()

    def get_version_count(self):
        """获取版本数量"""
        return self.versions.count()

    def get_main_file(self):
        """获取主文件"""
        return self.files.filter(is_main=True).first()

    def get_file_count(self):
        """获取文件数量"""
        return self.files.count()

    def get_total_size(self):
        """获取项目总大小（字节）"""
        return sum(f.file_size for f in self.files.all())

    def get_file_tree(self):
        """获取文件树结构"""
        files = self.files.all().order_by('file_path')
        tree = {}

        for file in files:
            parts = file.file_path.split('/')
            current = tree

            # 构建目录结构
            for i, part in enumerate(parts[:-1]):
                if part not in current:
                    current[part] = {'type': 'directory', 'children': {}}
                current = current[part]['children']

            # 添加文件
            filename = parts[-1]
            current[filename] = {'type': 'file', 'file_obj': file, 'is_main': file.is_main, 'size': file.file_size}

        return tree

    def soft_delete(self):
        """软删除代码"""
        self.is_deleted = True
        self.deleted_at = timezone.now()
        self.save(update_fields=['is_deleted', 'deleted_at'])

    def restore(self):
        """恢复已删除的代码"""
        self.is_deleted = False
        self.deleted_at = None
        self.save(update_fields=['is_deleted', 'deleted_at'])

    def delete(self, using=None, keep_parents=False):
        """重写delete方法，默认执行软删除"""
        self.soft_delete()

    def hard_delete(self):
        """物理删除代码（真正删除）"""
        super().delete()


class CodeFile(models.Model):
    """代码文件模型，支持多文件项目结构"""

    code = models.ForeignKey(Code, on_delete=models.CASCADE, related_name='files', verbose_name='代码项目')
    file_path = models.CharField(max_length=500, verbose_name='文件路径')  # 相对路径，如 src/main.py
    file_name = models.CharField(max_length=255, verbose_name='文件名')  # 文件名，如 main.py
    content = models.TextField(verbose_name='文件内容')
    file_size = models.PositiveIntegerField(default=0, verbose_name='文件大小(字节)')
    is_main = models.BooleanField(default=False, verbose_name='是否为主文件')  # 标记入口文件
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')

    class Meta:
        verbose_name = '代码文件'
        verbose_name_plural = '代码文件'
        unique_together = ['code', 'file_path']  # 同一项目下文件路径唯一
        ordering = ['file_path']

    def __str__(self):
        return f'{self.code.title}/{self.file_path}'

    def save(self, *args, **kwargs):
        # 从file_path提取file_name
        if self.file_path:
            self.file_name = os.path.basename(self.file_path)

        # 自动计算文件大小
        if self.content:
            self.file_size = len(self.content.encode('utf-8'))

        super().save(*args, **kwargs)

    @property
    def file_extension(self):
        """获取文件扩展名"""
        return os.path.splitext(self.file_name)[1].lower()

    @property
    def directory_path(self):
        """获取文件所在目录路径"""
        return os.path.dirname(self.file_path) if self.file_path else ''


class CodeVersion(models.Model):
    """代码版本模型，存储代码的不同版本（保留兼容性）"""

    code = models.ForeignKey(Code, on_delete=models.CASCADE, related_name='versions', verbose_name='代码')
    version_number = models.PositiveIntegerField(verbose_name='版本号')
    content = models.TextField(verbose_name='代码内容')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    file_size = models.PositiveIntegerField(default=0, verbose_name='文件大小(字节)')
    commit_message = models.CharField(max_length=200, blank=True, null=True, verbose_name='提交信息')

    class Meta:
        verbose_name = '代码版本'
        verbose_name_plural = '代码版本'
        ordering = ['-version_number']
        unique_together = ['code', 'version_number']

    def __str__(self):
        return f'{self.code.title} v{self.version_number}'

    def save(self, *args, **kwargs):
        # 计算文件大小
        if self.content:
            self.file_size = len(self.content.encode('utf-8'))

        # 如果没有设置版本号，则自动设置为最新版本号+1
        if not self.version_number:
            latest_version = self.code.versions.order_by('-version_number').first()
            self.version_number = 1 if not latest_version else latest_version.version_number + 1

        super().save(*args, **kwargs)
